from rest_framework import serializers
from orders.models import OrdersModel,OrdersDetailModel
from django_redis import get_redis_connection
from coupon.models import CouponLogModel
from django.db import transaction
import datetime
from course.models import CourseModel
from fuguang.utils import constants
import traceback
from decimal import Decimal
# ModelSerializer模型序列化器
# serializers.Serializer  普通序列化器

class OrderModelSerializer(serializers.ModelSerializer):
    user_coupon_id = serializers.IntegerField(write_only=True,default=None)
    class Meta():
        model = OrdersModel
        fields = ['id','pay_type','credit','user_coupon_id']
        extra_kwargs = {
            "pay_type":{"write_only":True},
            "credit":{"write_only":True}
        }
    # 新增数据
    def create(self, validated_data):
        # 往订单表中添加新订单
        # 获取用户,上下文context 获取
        user = self.context['request'].user
        user_id = user.id
        # 获取当前用户的下单商品,获取购物车的redis链接对象
        redis = get_redis_connection('cart')
        # 根据用户id，获取当前用户所有购物车数据
        cart_hash = redis.hgetall(f"cart_{user_id}")
        # 判断购物车中是否存在商品
        if len(cart_hash)<1:
            raise serializers.ValidationError(detail="购物车中没有商品",code="cart_empty")

        # 选择兑现的积分 , 用户所使用积分
        user_credit = int(validated_data.get('credit',0))

        # 判断 判断用户选择积分，是否超过自身拥有的积分
        if user_credit > 0 and user_credit > user.credit:
            raise serializers.ValidationError(detail="您本次积分不够划扣",code="credit_error")

        # 优惠券 获取用户使用的优惠券
        user_coupon_id = validated_data.get('user_coupon_id',None)
        user_coupon1 = None
        if user_coupon_id is not None:
            user_coupon1 = CouponLogModel.objects.filter(id=user_coupon_id,user_id=user_id).first()

        # 创建订单操作  开启数据库事务
        with transaction.atomic():
            # 创建事务的还原点
            t1 = transaction.savepoint()

            try:
                orders = OrdersModel.objects.create(
                    name="浮光商城购买下单",
                    user_id=user_id,
                    # 生成订单号                                                                         会导致位数不一致
                    order_number= datetime.datetime.now().strftime("%Y%m%d")+str(("%08d" % user_id)) + "%08d" % redis.incr('order_number'),
                    pay_type=validated_data.get('pay_type')
                )
                # 订单记录表创建完成，获取课程，生成订单详情数据，并外键增加
                # 获取到课程列表情况下，通过循环课程列表，计算课程可用积分
                # 获取最优的优惠券
                # 订单总价    优惠活动以后的总价
                # 课程总价：实付价格

                # 获取选中的课程
                course_id_list = [int(key.decode()) for key,value in cart_hash.items() if value==b'1']
                # 获取购物车中勾选商品的详细商品数据
                course_list = CourseModel.objects.filter(id__in=course_id_list,is_deleted=False,is_show=True)
                # 订单总价
                total_price = 0  # 本次下单总价
                real_price = 0  # 计算优惠活动的价格，总价，循环计算

                # max_user_credit = 0 # 积分   计算最多可以抵扣的积分

                # 最终折扣价格
                total_discount_price = 0  #最终折扣价格

                # 最优惠的课程
                max_discount_coutse = None

                # 积分 计算最多可以抵扣的积分
                max_use_credit = 0

                # 循环下单课程信息，需要将下单课程添加到详情表中
                detail_list = []
                for course in course_list:
                    # 获取当前课程的优惠价格，如果没有，则赋值当前原价
                    discount_price = course.discount.get('price',course.price)
                    discount_name = course.discount.get('type',"")

                    # 计算总价  --- 类型转换的报错
                    total_price += Decimal(course.price)
                    # 计算优惠总价
                    real_price += Decimal(discount_price)

                    detail_list.append(OrdersDetailModel(
                        order=orders,
                        course=course,
                        price=course.price,
                        real_price=discount_price,
                        discount_name=discount_name
                    ))

                    #  找到最优的优惠券
                    if user_coupon_id:
                        if max_discount_coutse is None:
                            max_discount_coutse = course
                        else:
                            # 循环当前课程价格，判断是否大于已经存在的最优课程的优惠价格
                            if course.price >= max_discount_coutse.price:
                                max_discount_coutse = course

                    if user_credit >0 and course.credit>0:
                        # 循环课程，获取最大可以使用积分
                        max_use_credit += course.credit
                # 一次性往数据库添加商品详情列表对象
                OrdersDetailModel.objects.bulk_create(detail_list)


                # 计算最终优惠价格
                if user_coupon1:
                    # 获取当前用户选择优惠券，获取id    -100  *0.8
                    sale = user_coupon1.coupon.sale[1:]
                    if user_coupon1.coupon.discount==1:
                        # 减免  ---  类型转换错误   最终优惠价格  优惠价格
                        total_discount_price = Decimal(sale)
                        # total_discount_price = real_price - float(sale)
                    elif user_coupon1.coupon.discount==2:
                        # 类型转换问题，报错
                        total_discount_price = max_discount_coutse.price * (1-Decimal(sale))

                # 积分
                if user_credit >0 :
                        # 500             100
                    if max_use_credit < user_credit:
                        raise serializers.ValidationError(detail="超过当前最大可用积分限制",code="credit_max")

                    # 给当前订单，赋值，赋使用的积分
                    orders.credit = user_credit
                    # 把积分按公式换算称钱
                    total_discount_price = Decimal(user_credit/constants.CREDIT_TO_MONEY)
                    # 扣除用户积分   用户当前拥有积分，减去本次下单使用积分
                    user.credit = user.credit - user_credit
                    user.save()

                # 给订单赋值，课程总价、实际付款金额
                orders.total_price = total_price
                # 实际付款金额
                orders.real_price = Decimal(real_price) - total_discount_price
                orders.save()

                # 购物车数据，需要删除
                cart = {key:value for key,value in cart_hash.items() if value == b'0'}

                pipe = redis.pipeline()
                pipe.multi()
                pipe.delete(f"cart_{user_id}")
                if len(cart)>0:
                    pipe.hset(f"cart_{user_id}",mapping=cart)
                pipe.execute()


                # 优惠券删除,优先判断用户是否使用优惠券
                if user_coupon1:
                    # 将优惠券从redis中删除
                    # 将优惠券信息，绑定到订单中
                    user_coupon1.order = orders
                    redis = get_redis_connection('coupon')
                    redis.delete(f"{user_id}:{user_coupon_id}")

                return orders

            except Exception as es:
                print('当前订单生成失败....')
                print(es)
                # 打印异常的类型和描述
                print(f"An error occurred: {type(es).__name__} - {es}")
                # 打印异常的完整堆栈信息
                traceback.print_exc()
                # 事务回滚
                transaction.savepoint_rollback(t1)
                raise serializers.ValidationError(detail="订单生成失败，请稍后再试...",code="order_error")


class OrderDetailModelSerializer(serializers.ModelSerializer):
    course_id = serializers.IntegerField(source="course.id")
    course_name = serializers.CharField(source='course.name')
    course_cover = serializers.ImageField(source='course.course_cover')
    class Meta():
        model = OrdersDetailModel
        fields = ['id','price','real_price','discount_name','course_id','course_name','course_cover']


class OrderListModelSerializer(serializers.ModelSerializer):
    order_detail = OrderDetailModelSerializer(many=True)
    class Meta():
        model = OrdersModel
        fields = ['id','total_price','real_price','order_number','order_status','pay_type','order_desc','pay_time','credit','coupon','order_detail','created_time']